UT拦截统计 - #13
Conversation
utf8mb4 下 VARCHAR(1024) 全列与 created_at 联合索引超过 3072 字节上限。 改为 mr_url(191) 前缀索引,ORM mysql_length 与 spec §5.3 同步。 Co-authored-by: Cursor <cursoragent@cursor.com>
修复 TS2345:onChange 为 [Dayjs|null, Dayjs|null]|null,state 不可写死为 [Dayjs,Dayjs]。 Co-authored-by: Cursor <cursoragent@cursor.com>
📝 WalkthroughWalkthroughThis PR implements a complete UT gate run reporting feature enabling Jenkins integration to persist test gate results and a frontend history page for browsing and filtering those results. It includes database schema, ORM models, REST APIs with idempotency and integration token authentication, comprehensive request validation, and a React-based UI with filtering and pagination. ChangesUT Gate Run Reporting and History
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Poem
🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Warning Review ran into problems🔥 ProblemsGit: Failed to clone repository. Please run the Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (1)
spec/16_ut_gate_report_post_api_spec.md (1)
69-70: ⚡ Quick winMake unknown-field handling deterministic.
这里同时允许“忽略未知键”或“422”两种行为,会导致实现与联调口径漂移。建议在本文档内固定一种(推荐
extra="ignore"),并与 OpenAPI/测试保持一致。🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@spec/16_ut_gate_report_post_api_spec.md` around lines 69 - 70, The spec currently permits two behaviors for unknown keys in ut_gate_run (ignore or return 422), causing nondeterministic implementations; fix by standardizing on Pydantic's extra="ignore" behavior: update the ut_gate_run schema handling to ignore unknown fields such as error_message, git_remote_url, git_commit_sha, mr_id, summary_line, and ensure the OpenAPI document and tests (including any validation in the POST/PUT handler that constructs or validates ut_gate_run) explicitly reflect extra="ignore" so runtime, API docs, and tests are consistent.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@docs/05_technical_architecture.md`:
- Line 227: The doc currently contradicts itself about Jenkins interaction;
update the technical architecture text so the data flow is consistently "Jenkins
→ Backend API → MySQL": modify the ut_gate_run row (the line referencing POST
/api/v1/ut-gate-runs and UT_GATE_INTEGRATION_TOKEN) to explicitly state Jenkins
posts to Backend API which authenticates using UT_GATE_INTEGRATION_TOKEN and the
Backend writes to MySQL, and remove or revise the earlier sentence that claims
"Jenkins 无直接交互、直接写 MySQL" so it reflects the single path; ensure references to
spec/16_ut_gate_report_post_api_spec.md and the endpoint POST
/api/v1/ut-gate-runs remain and clearly document the security boundary at the
Backend API.
In `@frontend/src/pages/ut-gate-history/UtGateHistoryPage.tsx`:
- Around line 106-114: The reset handler onReset calls fetchList(1, 20) before
the state setters (setDateRange, setInterceptFilter, setMrUrlExact,
setMrUrlContains, setJobNameContains, setPageSize) have taken effect, so the
request uses stale filters; instead invoke fetchList with the explicit
reset/default parameters (e.g. page=1, size=20, dateRange=null,
interceptFilter="all", mrUrlExact="", mrUrlContains="", jobNameContains="") or
adjust fetchList to accept an overrides object and pass those defaults from
onReset so the network call uses the intended cleared filters rather than
relying on pending state updates.
In `@spec/18_ut_gate_history_frontend_spec.md`:
- Around line 129-130: The spec must be updated to require that large ids are
transmitted as JSON strings or parsed with a big-number aware parser before
JSON.parse so precision isn't lost; change any guidance around using BigInt or
String(row.id) to explicitly state that BigInt conversion only works if the
backend sends ids as strings (e.g., "id":"12345678901234567890") or the client
uses a specialized parser like json-bigint to preserve integers >
Number.MAX_SAFE_INTEGER prior to any JSON.parse, and add a note that converting
a numeric value to BigInt after a standard JSON.parse cannot recover lost
precision.
---
Nitpick comments:
In `@spec/16_ut_gate_report_post_api_spec.md`:
- Around line 69-70: The spec currently permits two behaviors for unknown keys
in ut_gate_run (ignore or return 422), causing nondeterministic implementations;
fix by standardizing on Pydantic's extra="ignore" behavior: update the
ut_gate_run schema handling to ignore unknown fields such as error_message,
git_remote_url, git_commit_sha, mr_id, summary_line, and ensure the OpenAPI
document and tests (including any validation in the POST/PUT handler that
constructs or validates ut_gate_run) explicitly reflect extra="ignore" so
runtime, API docs, and tests are consistent.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 8446cc35-63c9-4224-b9e8-e8cfc5c5acf5
📒 Files selected for processing (24)
.env.examplebackend/api/router.pybackend/api/v1/ut_gate_run.pybackend/core/config.pybackend/core/dependencies.pybackend/models/__init__.pybackend/models/ut_gate_run.pybackend/schemas/ut_gate_run.pybackend/services/schema_check_service.pybackend/services/ut_gate_run_service.pybackend/tests/test_openapi.pybackend/tests/test_ut_gate_run_query.pybackend/tests/test_ut_gate_run_service.pydatabase/V1.1.2__create_ut_gate_run.sqldocs/05_technical_architecture.mdfrontend/src/layouts/MainLayout.tsxfrontend/src/pages/ut-gate-history/UtGateHistoryPage.tsxfrontend/src/routes/index.tsxfrontend/src/services/index.tsfrontend/src/services/utGate.tsspec/15_ut_gate_jenkins_report_spec.mdspec/16_ut_gate_report_post_api_spec.mdspec/17_ut_gate_runs_get_api_spec.mdspec/18_ut_gate_history_frontend_spec.md
| | case_offline_type | 全表 | 全字段 CRUD | 管理员操作 | | ||
| | sys_audit_log | 全表 | INSERT only | 系统自动写入 | | ||
| | report_snapshot | 全表 | INSERT / SELECT | 管理员生成报告时写入 | | ||
| | ut_gate_run | 全表 | INSERT(幂等) | Jenkins 经 `POST /api/v1/ut-gate-runs` 写入,鉴权为 `UT_GATE_INTEGRATION_TOKEN`(见 `spec/16_ut_gate_report_post_api_spec.md`) | |
There was a problem hiding this comment.
统一 Jenkins 数据流描述,避免架构口径冲突。
这里写的是 Jenkins 通过 POST /api/v1/ut-gate-runs 写入;但文档前文仍有“Jenkins 无直接交互、直接写 MySQL”的描述。建议统一为单一路径:Jenkins → Backend API → MySQL,避免实现和安全边界被误读。
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@docs/05_technical_architecture.md` at line 227, The doc currently contradicts
itself about Jenkins interaction; update the technical architecture text so the
data flow is consistently "Jenkins → Backend API → MySQL": modify the
ut_gate_run row (the line referencing POST /api/v1/ut-gate-runs and
UT_GATE_INTEGRATION_TOKEN) to explicitly state Jenkins posts to Backend API
which authenticates using UT_GATE_INTEGRATION_TOKEN and the Backend writes to
MySQL, and remove or revise the earlier sentence that claims "Jenkins 无直接交互、直接写
MySQL" so it reflects the single path; ensure references to
spec/16_ut_gate_report_post_api_spec.md and the endpoint POST
/api/v1/ut-gate-runs remain and clearly document the security boundary at the
Backend API.
| const onReset = () => { | ||
| setDateRange(null); | ||
| setInterceptFilter("all"); | ||
| setMrUrlExact(""); | ||
| setMrUrlContains(""); | ||
| setJobNameContains(""); | ||
| setPageSize(20); | ||
| void fetchList(1, 20); | ||
| }; |
There was a problem hiding this comment.
Reset currently queries with pre-reset filters
Line 113 calls fetchList(1, 20) before Lines 107-112 state updates take effect, so the request can still carry old filter values from the callback closure.
Suggested fix
- const fetchList = useCallback(async (nextPage: number, nextPageSize: number) => {
- if (mrUrlExact.trim() && mrUrlContains.trim()) {
+ type FetchOverrides = Partial<{
+ dateRange: UtGateDateRange;
+ interceptFilter: "all" | "yes" | "no";
+ mrUrlExact: string;
+ mrUrlContains: string;
+ jobNameContains: string;
+ }>;
+
+ const fetchList = useCallback(async (nextPage: number, nextPageSize: number, overrides?: FetchOverrides) => {
+ const exact = (overrides?.mrUrlExact ?? mrUrlExact).trim();
+ const contains = (overrides?.mrUrlContains ?? mrUrlContains).trim();
+ const jobContains = (overrides?.jobNameContains ?? jobNameContains).trim();
+ const appliedDateRange = overrides?.dateRange ?? dateRange;
+ const appliedIntercept = overrides?.interceptFilter ?? interceptFilter;
+
+ if (exact && contains) {
message.warning("MR 精确与 MR 子串互斥,请只填其一");
return;
}
@@
- if (dateRange?.[0]) params.start_time = dateRange[0].format("YYYY-MM-DD");
- if (dateRange?.[1]) params.end_time = dateRange[1].format("YYYY-MM-DD");
- if (interceptFilter === "yes") params.is_intercepted = true;
- if (interceptFilter === "no") params.is_intercepted = false;
- const m = mrUrlExact.trim();
- const mc = mrUrlContains.trim();
- if (m) params.mr_url = m;
- if (mc) params.mr_url_contains = mc;
- const j = jobNameContains.trim();
- if (j) params.job_name_contains = j;
+ if (appliedDateRange?.[0]) params.start_time = appliedDateRange[0].format("YYYY-MM-DD");
+ if (appliedDateRange?.[1]) params.end_time = appliedDateRange[1].format("YYYY-MM-DD");
+ if (appliedIntercept === "yes") params.is_intercepted = true;
+ if (appliedIntercept === "no") params.is_intercepted = false;
+ if (exact) params.mr_url = exact;
+ if (contains) params.mr_url_contains = contains;
+ if (jobContains) params.job_name_contains = jobContains;
@@
- const onReset = () => {
+ const onReset = () => {
setDateRange(null);
setInterceptFilter("all");
setMrUrlExact("");
setMrUrlContains("");
setJobNameContains("");
+ setPage(1);
setPageSize(20);
- void fetchList(1, 20);
+ void fetchList(1, 20, {
+ dateRange: null,
+ interceptFilter: "all",
+ mrUrlExact: "",
+ mrUrlContains: "",
+ jobNameContains: "",
+ });
};🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@frontend/src/pages/ut-gate-history/UtGateHistoryPage.tsx` around lines 106 -
114, The reset handler onReset calls fetchList(1, 20) before the state setters
(setDateRange, setInterceptFilter, setMrUrlExact, setMrUrlContains,
setJobNameContains, setPageSize) have taken effect, so the request uses stale
filters; instead invoke fetchList with the explicit reset/default parameters
(e.g. page=1, size=20, dateRange=null, interceptFilter="all", mrUrlExact="",
mrUrlContains="", jobNameContains="") or adjust fetchList to accept an overrides
object and pass those defaults from onReset so the network call uses the
intended cleared filters rather than relying on pending state updates.
| - **`id`**:`BIGINT` 可能超过 **`Number.MAX_SAFE_INTEGER`**。表格展示推荐 **`String(row.id)`** 或使用 **`BigInt`** 再转字符串;**避免**对大 `id` 做依赖精度的数值运算。 | ||
| - **日期时间**:后端返回 ISO 字符串;展示层可用 **`dayjs`**(若项目已用)或 **`toLocaleString`** 格式化,**不**强制与时区策略改动后端。 |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
In JavaScript, if JSON contains an integer larger than Number.MAX_SAFE_INTEGER, can converting the parsed Number to BigInt recover the original exact integer?
💡 Result:
No, converting a parsed Number to BigInt cannot recover the original exact integer if the number exceeded Number.MAX_SAFE_INTEGER [1][2]. When JSON.parse encounters a number, it parses it into a JavaScript Number type, which follows the IEEE 754 double-precision floating-point format [3][4]. This format has a limited mantissa (53 bits), meaning it can only represent integers exactly within the range of -(2^53 - 1) to 2^53 - 1 (Number.MAX_SAFE_INTEGER) [1]. If a JSON number exceeds this range, the precision is lost during the initial parsing process [5][2]. The value is rounded to the nearest representable double-precision float [4]. Because this rounding occurs before you can access the value or convert it to a BigInt, the original exact integer information is already discarded [6][2]. To handle integers larger than Number.MAX_SAFE_INTEGER without losing precision, you must prevent the JSON parser from converting them into standard Numbers [2]. Common strategies include: 1. Using a specialized library (e.g., json-bigint) that parses large numbers as strings or BigInts directly [7][2]. 2. Pre-processing the JSON string to wrap large numbers in quotes (converting them to strings) before passing them to JSON.parse [7][4][8]. 3. Using the reviver parameter of JSON.parse in conjunction with the raw source text (if the environment provides access to it via context) to manually parse the original string representation as a BigInt [9][6]. Note that the standard reviver function receives the already-parsed (and thus already corrupted) Number, so it cannot recover the lost precision on its own [6][2].
Citations:
- 1: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/MAX_SAFE_INTEGER
- 2: https://thedebuggersitsolutions.com/blog/how-to-parse-bigint-json
- 3: https://stackoverflow.com/questions/58406880/calling-parseint-with-a-string-which-represents-a-value-larger-than-number-max-s
- 4: https://stackoverflow.com/questions/10631494/json-parse-parses-converts-big-numbers-incorrectly
- 5: https://stackoverflow.com/questions/62231000/how-to-properly-parse-a-json-string-containing-very-large-numbers
- 6: https://medium.com/@slavafomin/one-doesnt-simply-parse-this-json-in-javascript-33c1929ad690
- 7: https://stackoverflow.com/questions/18755125/node-js-is-there-any-proper-way-to-parse-json-with-large-numbers-long-bigin/18755261
- 8: https://medium.com/@tanmaypanda752/how-to-parse-bigint-from-json-682f03c4e675
- 9: https://stackoverflow.com/questions/69644298/how-to-make-json-parse-to-treat-all-the-numbers-as-bigint
Clarify how large id values are transmitted and parsed to prevent precision loss.
The spec suggests using BigInt to handle id values exceeding Number.MAX_SAFE_INTEGER, but this only works if the backend transmits large ids as JSON strings, not as JSON numbers. If the backend sends large ids as JSON numbers, precision is already lost at the JSON.parse stage—converting to BigInt afterwards cannot recover it (IEEE 754 double-precision can only represent integers exactly up to 2^53−1).
The spec should explicitly require: either the backend must send large ids as strings in the JSON response, or use a specialized JSON parser (e.g., json-bigint) that handles large numbers before precision loss occurs. Relying on post-parse BigInt conversion is insufficient.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@spec/18_ut_gate_history_frontend_spec.md` around lines 129 - 130, The spec
must be updated to require that large ids are transmitted as JSON strings or
parsed with a big-number aware parser before JSON.parse so precision isn't lost;
change any guidance around using BigInt or String(row.id) to explicitly state
that BigInt conversion only works if the backend sends ids as strings (e.g.,
"id":"12345678901234567890") or the client uses a specialized parser like
json-bigint to preserve integers > Number.MAX_SAFE_INTEGER prior to any
JSON.parse, and add a note that converting a numeric value to BigInt after a
standard JSON.parse cannot recover lost precision.
Summary by CodeRabbit
New Features
/api/v1/ut-gate-runsendpoints for reporting and retrieving UT gate test results.Documentation